home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / bootstrap / bootstrap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-18  |  32.8 KB  |  1,435 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    backendsup.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    "backend" program support routines.
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *
  10.  *   NOTES
  11.  *
  12.  *   IDENTIFICATION
  13.  *    $Header: /private/postgres/src/bootstrap/RCS/bootstrap.c,v 1.15 1992/08/24 23:12:50 mao Exp $
  14.  * ----------------------------------------------------------------
  15.  */
  16.  
  17. #include <signal.h>
  18.  
  19. #include "tmp/postgres.h"
  20. #include "tcop/tcopprot.h"
  21.  
  22. RcsId("$Header: /private/postgres/src/bootstrap/RCS/bootstrap.c,v 1.15 1992/08/24 23:12:50 mao Exp $");
  23.  
  24. #include "access/heapam.h"
  25. #include "access/tqual.h"
  26. #include "tmp/miscadmin.h"
  27. #include "utils/exc.h"    /* for ExcAbort and <setjmp.h> */
  28. #include "utils/fmgr.h"
  29. #include "utils/mcxt.h"
  30. #include "storage/smgr.h"
  31.  
  32. #include "catalog/pg_type.h"
  33.  
  34. #undef BOOTSTRAP
  35. #include "y.tab.h"
  36.  
  37. /* ----------------
  38.  *    prototypes
  39.  *
  40.  *      NOTE: see also bkint.h
  41.  * ----------------
  42.  */
  43. #include "support/bkint.h"
  44.  
  45. #ifndef linux
  46. extern int setjmp();
  47. #endif
  48. extern int chdir();
  49. extern char *getenv();
  50.  
  51. void SocketBackend ARGS((char *, LispValue));
  52. void InteractiveBackend ARGS((char *, LispValue));
  53. void EvalLine ARGS((char *, LispValue));
  54. bool BootstrapAlreadySeen ARGS(( ObjectId id ));
  55.  
  56. /* ----------------
  57.  *    global variables
  58.  * ----------------
  59.  */
  60. /*
  61.  * In the lexical analyzer, we need to get the reference number quickly from
  62.  * the string, and the string from the reference number.  Thus we have
  63.  * as our data structure a hash table, where the hashing key taken from
  64.  * the particular string.  The hash table is chained.  One of the fields
  65.  * of the hash table node is an index into the array of character pointers.
  66.  * The unique index number that every string is assigned is simply the
  67.  * position of its string pointer in the array of string pointers.
  68.  */
  69.  
  70. char pg_pathname[256];
  71.  
  72. macro        *strtable [STRTABLESIZE];
  73. hashnode    *hashtable [HASHTABLESIZE];
  74.  
  75. FILE        *source = NULL;
  76. static int    strtable_end = -1;    /* Tells us last occupied string space */
  77. static int    num_of_errs = 0;      /* Total number of errors encountered */
  78.  
  79. static char *   (typestr[16]) = {
  80.     "bool", "bytea", "char", "char16", "dt", "int2", "int28",
  81.     "int4", "regproc", "text", "oid", "tid", "xid", "iid",
  82.     "oid8", "smgr"
  83. };
  84.  
  85. /* functions associated with each type */
  86. static    long    Procid[16][7] = {
  87.     { 16, 1, 0, F_BOOLIN, F_BOOLOUT, F_BOOLEQ, 0 },
  88.     { 17, -1, 1, F_BYTEAIN, F_BYTEAOUT, 0, 0 },
  89.     { 18, 1, 0, F_CHARIN, F_CHAROUT, F_CHAREQ, 0 },
  90.     { 19, 16, 1, F_CHAR16IN, F_CHAR16OUT, F_CHAR16EQ, 0 },
  91.     { 20, 4, 0, F_DATETIMEIN, F_DATETIMEOUT, 0, 0 },
  92.     { 21, 2, 0, F_INT2IN, F_INT2OUT, F_INT2EQ, F_INT2LT },
  93.     { 22, 16, 1, F_INT28IN, F_INT28OUT, 0, 0 },
  94.     { 23, 4, 0, F_INT4IN, F_INT4OUT, F_INT4EQ, F_INT4LT },
  95.     { 24, 4, 0, F_REGPROCIN, F_REGPROCOUT, 0, 0 },
  96.     { 25, -1, 1, F_TEXTIN, F_TEXTOUT, F_TEXTEQ, 0 },
  97.     { 26, 4, 0, F_INT4IN, F_INT4OUT, F_INT4EQ, 0 },
  98.     { 27, 6, 1, F_TIDIN, F_TIDOUT, 0, 0 },
  99.     { 28, 5, 1, F_XIDIN, F_XIDOUT, 0, 0 },
  100.     { 29, 1, 0, F_CIDIN, F_CIDOUT, 0, 0 },
  101.     { 30, 32, 1, F_OID8IN, F_OID8OUT, 0, 0 },
  102.     {210, 2, 0, F_SMGRIN, F_SMGROUT, F_SMGREQ, 0 }
  103. };
  104.  
  105. struct    typmap {            /* a hack */
  106.     ObjectId    am_oid;
  107.     struct type    am_typ;
  108. };
  109.  
  110. #ifdef    EBUG
  111. static    int    ShowLock = 0;
  112. #endif
  113.  
  114. static    struct    typmap    **Typ = (struct typmap **)NULL;
  115. static    struct    typmap    *Ap = (struct typmap *)NULL;
  116.  
  117. extern int    Quiet;
  118. static    int        Warnings = 0;
  119. static    int        ShowTime = 0;
  120. static    char        Blanks[MAXATTR];
  121. static    char        Buf[MAXPGPATH];
  122. static TimeQual        StandardTimeQual = NowTimeQual;
  123. static TimeQualSpace    StandardTimeQualSpace;
  124.  
  125. int        Userid;
  126. Relation    reldesc;        /* current relation descritor */
  127. char        relname[80];        /* current relation name */
  128. struct    attribute *attrtypes[MAXATTR];  /* points to attribute info */
  129. char        *values[MAXATTR];    /* cooresponding attribute values */
  130. int        numattr;        /* number of attributes for cur. rel */
  131. jmp_buf        Warn_restart;
  132. int        DebugMode;
  133. static int UseBackendParseY = 0;
  134.  
  135. extern bool override;
  136.  
  137. extern    int    optind;
  138. extern    char    *optarg;
  139.  
  140.  
  141. /* ----------------------------------------------------------------
  142.  *            misc functions
  143.  * ----------------------------------------------------------------
  144.  */
  145. /* ----------------
  146.  *    hack so linker links 
  147.  * ----------------
  148.  */
  149.  
  150. /* ----------------
  151.  *    error handling / abort routines
  152.  * ----------------
  153.  */
  154. void
  155. err()
  156. {
  157.     cleanup();
  158.     exitpg(1);
  159. }
  160.  
  161.  
  162. /* ----------------------------------------------------------------
  163.  *                BootstrapMain
  164.  * ----------------------------------------------------------------
  165.  */
  166. void
  167. BootstrapMain(ac, av)
  168. int  ac;
  169. char *av[];
  170. {
  171.     int      i;
  172.     int      flagC, flagQ;
  173.     int      portFd = -1;
  174.     char  *dat;
  175.     char  pathbuf[128], *getwd();
  176.     extern char *DBName;
  177.  
  178.     /* ----------------
  179.      *    initialize signal handlers
  180.      * ----------------
  181.      */
  182.     signal(SIGHUP, die);
  183.     signal(SIGINT, die);
  184.     signal(SIGTERM, die);
  185.  
  186.     /* ----------------
  187.      *    process command arguments
  188.      * ----------------
  189.      */
  190.     Quiet = 0;
  191.     flagC = 0;
  192.     flagQ = 0;
  193.     dat = NULL;
  194.  
  195.     for (i = 2; i < ac; ++i) {
  196.     char *ptr = av[i];
  197.     if (*ptr != '-') {
  198.         if (dat != NULL) {
  199.         fputs("DB Name specified twice!\n", stderr);
  200.         goto usage;
  201.         }
  202.         DBName = dat = ptr;
  203.         continue;
  204.     }
  205.  
  206.     while (*++ptr) {
  207.         switch(*ptr) {
  208.         case 'd':    /* -debug mode */
  209.         DebugMode = 1;
  210.         ptr = "\0";
  211.         break;
  212.         case 'a':    /* -ami    */
  213.         UseBackendParseY = 1;
  214.         ptr = "\0";    /* \0\0 */
  215.         break;
  216.         case 'C':
  217.             flagC = 1;
  218.         break;
  219.         case 'Q':
  220.         flagQ = 1;
  221.         break;
  222.         case 'O':
  223.         override = true;
  224.         break;
  225.         case 'p':    /* started by postmaster */
  226.         IsUnderPostmaster = true;
  227.         ptr = "\0";    /* \0\0 */
  228.         break;
  229.         case 'P':
  230.         portFd = atoi(ptr + 1);
  231.         ptr = "\0";
  232.         break;
  233.         default:
  234.         fprintf(stderr, "Option %c is illegal\n", *ptr);
  235.         goto usage;
  236.         }
  237.     }
  238.     }
  239.     if (dat == NULL)
  240.     DBName = dat = getenv("USER");
  241.     if (dat == NULL) {
  242.     fputs("backend: failed, no db name specified\n", stderr);
  243.     fputs("         and no USER enviroment variable\n", stderr);
  244.     exitpg(1);
  245.     }
  246.  
  247.     Noversion = flagC;
  248.     Quiet = flagQ;
  249.  
  250.     /* ----------------
  251.      *    initialize input fd
  252.      * ----------------
  253.      */
  254.     if (IsUnderPostmaster == true && portFd < 0) {
  255.     fputs("backend: failed, no -P option with -postmaster opt.\n", stderr);
  256.     exitpg(1);
  257.     }
  258.     if (portFd >= 0)
  259.     SetPQSocket(portFd);
  260.  
  261.     /* ----------------
  262.      *    backend initialization
  263.      * ----------------
  264.      */
  265.     /* XXX the -C version flag should be removed and combined with -O */
  266.     GetDataHome();
  267.     SetProcessingMode((override) ? BootstrapProcessing : InitProcessing);
  268.     InitPostgres((String)dat);
  269.     LockDisable(true);
  270.     dat = Blanks;
  271.     
  272.     for (i = MAXATTR - 1; i >= 0; --i) {
  273.     attrtypes[i]=(struct attribute *)NULL;
  274.     *dat++ = ' ';
  275.     }
  276.     for(i = 0; i < STRTABLESIZE; ++i)
  277.     strtable[i] = NULL;                    
  278.     for(i = 0; i < HASHTABLESIZE; ++i)
  279.     hashtable[i] = NULL;                   
  280.  
  281.     /* ----------------
  282.      *    abort processing resumes here
  283.      * ----------------
  284.      */
  285.     signal(SIGHUP, handle_warn);
  286.     if (setjmp(Warn_restart) != 0) {
  287.     Warnings++;
  288.     AbortCurrentTransaction();
  289.     }
  290.  
  291.     /* ----------------
  292.      *    process input.
  293.      * ----------------
  294.      */
  295.     for (;;) {
  296.     Int_yyparse();
  297.     }
  298.  
  299.     /* ----------------
  300.      *    usage
  301.      * ----------------
  302.      */
  303. usage:
  304.     fputs("Usage: backend [-C] [-Q] [datname]\n", stderr);
  305.     exitpg(1);
  306. }
  307.  
  308. /* ----------------------------------------------------------------
  309.  *        MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
  310.  * ----------------------------------------------------------------
  311.  */
  312.  
  313. /* ----------------
  314.  *      createrel
  315.  *
  316.  *    takes the name of the relation to create, creates the file
  317.  *    and sticks the relation into the syscat.  if the relation
  318.  *    already exists in the syscat, then nothing is created
  319.  *    
  320.  *    Note : createrel creates, but does not open the named relation
  321.  * ----------------
  322.  */
  323. void
  324. createrel(name)
  325.     char *name;
  326. {
  327.     ObjectId toid;
  328.  
  329.     if (strlen(name) > 79) 
  330.     name[79] ='\000';
  331.     
  332.     bcopy(name,relname,strlen(name)+1);
  333.  
  334.     printf("Amcreatr: relation %s.\n", relname);
  335.  
  336.     if ((numattr == 0) || (attrtypes == NULL)) {
  337.     elog(WARN,"Warning: must define attributes before creating rel.\n");
  338.     elog(WARN,"         relation not created.\n");
  339.     } else {
  340.     reldesc = heap_creatr(relname, numattr, DEFAULT_SMGR, attrtypes);
  341.     if (reldesc == (Relation)NULL) {
  342.         elog(WARN,"Warning: cannot create relation %s.\n", relname);
  343.         elog(WARN,"         Probably should delete old %s.\n", relname);
  344.     }
  345.     toid = TypeDefine(relname, reldesc->rd_id, -1, -1, 'c', ',',
  346.               "textin", "textout", "textin", "textout",
  347.               NULL, "-", (Boolean) 0);
  348.  
  349.     }
  350. }
  351.  
  352. /* ----------------
  353.  *    boot_openrel
  354.  * ----------------
  355.  */
  356. void
  357. boot_openrel(name)
  358.     char *name;
  359. {
  360.     int        i;
  361.     struct    typmap    **app;
  362.     Relation    rdesc;
  363.     HeapScanDesc    sdesc;
  364.     HeapTuple    tup;
  365.     extern    char    TYPE_R[];
  366.     
  367.     if(strlen(name) > 79) 
  368.     name[79] ='\000';
  369.     bcopy(name, relname, strlen(name)+1);
  370.     
  371.     if (Typ == (struct typmap **)NULL) {
  372.     StartPortalAllocMode(DefaultAllocMode, 0);
  373.     rdesc = heap_openr(TYPE_R);
  374.     sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
  375.       for (i=0; PointerIsValid(tup=heap_getnext(sdesc,0,(Buffer *)NULL)); ++i);
  376.     heap_endscan(sdesc);
  377.     app = Typ = ALLOC(struct typmap *, i + 1);
  378.     while (i-- > 0)
  379.         *app++ = ALLOC(struct typmap, 1);
  380.     *app = (struct typmap *)NULL;
  381.     sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
  382.     app = Typ;
  383.     while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL))) {
  384.         (*app)->am_oid = tup->t_oid;
  385.         bcopy(
  386.         (char *)GETSTRUCT(tup), 
  387.         (char *)&(*app++)->am_typ, 
  388.         sizeof ((*app)->am_typ)
  389.         );
  390.     }
  391.     heap_endscan(sdesc);
  392.     heap_close(rdesc);
  393.     EndPortalAllocMode();
  394.     }
  395.     
  396.     if (reldesc != NULL) {
  397.     closerel(NULL);
  398.     }
  399.  
  400.     if (!Quiet)
  401.         printf("Amopen: relation %s. attrsize %d\n", relname, 
  402.         sizeof(struct attribute));
  403.     
  404.     reldesc = heap_openr(relname);
  405.     Assert(reldesc);
  406.     numattr = reldesc->rd_rel->relnatts;
  407.     for (i = 0; i < numattr; i++) {
  408.     if (attrtypes[i] == NULL) {
  409.         attrtypes[i] = AllocateAttribute();
  410.     }
  411.     bcopy(
  412.         (char *)reldesc->rd_att.data[i], 
  413.         (char *)attrtypes[i],
  414.         sizeof (*attrtypes[0])
  415.     );
  416.     if (DebugMode) {
  417.         struct attribute *at = attrtypes[i];
  418.         printf("create attribute %d name %s len %d num %d type %d\n",
  419.         i, at->attname, at->attlen, at->attnum, at->atttypid
  420.         );
  421.         fflush(stdout);
  422.     }
  423.     }
  424. }
  425.  
  426. /* ----------------
  427.  *    closerel
  428.  * ----------------
  429.  */
  430. void
  431. closerel(name)
  432.     char *name;
  433. {
  434.     /* ### insert errorchecking to make sure closing same relation we
  435.      *  have already open
  436.      */
  437.  
  438.     if (reldesc == NULL) {
  439.     elog(WARN,"Warning: no opened relation to close.\n");
  440.     } else {
  441.     if (!Quiet) printf("Amclose: relation %s.\n", relname);
  442.     heap_close(reldesc);
  443.     reldesc = (Relation)NULL;
  444.     }
  445. }
  446.  
  447. /* ----------------
  448.  *    printrel
  449.  * ----------------
  450.  */
  451. void
  452. printrel()
  453. {
  454.     HeapTuple        tuple;
  455.     HeapScanDesc    scandesc;
  456.     int            i;
  457.     Buffer        b;
  458.  
  459.     if (Quiet)
  460.     return;
  461.     if (reldesc == NULL) {
  462.     elog(WARN,"Warning: need to open relation to print.\n");
  463.     return;
  464.     }
  465.     /* print the name of the attributes in the relation */
  466.     printf("Relation %s:  ", relname);
  467.     printf("[ ");
  468.     for (i=0; i < reldesc->rd_rel->relnatts; i++)
  469.     printf("%s ", &reldesc->rd_att.data[i]->attname);
  470.     printf("]\n\n");
  471.     StartPortalAllocMode(DefaultAllocMode, 0);
  472.     
  473.     /* print the tuples in the relation */
  474.     scandesc = heap_beginscan(reldesc, 
  475.                   0,
  476.                   NowTimeQual,
  477.                   (unsigned) 0,
  478.                   (ScanKey) NULL);
  479.     while ((tuple = heap_getnext(scandesc, 0, &b)) != NULL) {
  480.     showtup(tuple, b, reldesc);
  481.     }
  482.     heap_endscan(scandesc);
  483.     EndPortalAllocMode();
  484.     printf("\nEnd of relation\n");
  485. }
  486.  
  487.  
  488. #ifdef    EBUG
  489. /* ----------------
  490.  *    randomprintrel
  491.  * ----------------
  492.  */
  493. void
  494. randomprintrel()
  495. {
  496.     HeapTuple        tuple;
  497.     HeapScanDesc    scandesc;
  498.     Buffer        buffer;
  499.     int            i, j, numattr, typeindex;
  500.     int            count;
  501.     int            mark = 0;
  502.     static bool        isInitialized = false;
  503.     extern        srandom();
  504.     long        random();
  505.     long        time();
  506.  
  507.     StartPortalAllocMode(DefaultAllocMode, 0);
  508.     if (reldesc == NULL) {
  509.     elog(WARN,"Warning: need to open relation to (r) print.\n");
  510.     } else {
  511.     /* print the name of the attributes in the relation */
  512.     printf("Relation %s:  ", relname);
  513.     printf("[ ");
  514.     for (i=0; i<reldesc->rd_rel->relnatts; i++) {
  515.         printf("%s ", &reldesc->rd_att.data[i]->attname);
  516.     }
  517.     printf(
  518.         "]\nWill display %d tuples in a slightly random order\n\n",
  519.         count = 64
  520.     );
  521.     
  522.     /* print the tuples in the relation */
  523.     if (! isInitialized) {
  524.         srandom((int)time(0));
  525.         isInitialized = true;
  526.     }
  527.     scandesc = heap_beginscan(reldesc, 
  528.                    random()&1, 
  529.                    NowTimeQual,
  530.                    0, 
  531.                    (ScanKey) NULL);
  532.     
  533.     numattr = reldesc->rd_rel->relnatts;
  534.     while (count-- != 0) {
  535.         if (!(random() & 0xf)) {
  536.         printf("\tRESTARTING SCAN\n");
  537.         heap_rescan(scandesc, random()&01, (ScanKey)NULL);
  538.         mark = 0;
  539.         }
  540.         if (!(random() & 0x3)) {
  541.         if (mark) {
  542.             printf("\tRESTORING MARK\n");
  543.             heap_restrpos(scandesc);
  544.             mark &= random();
  545.         } else {
  546.             printf("\tSET MARK\n");
  547.             heap_markpos(scandesc);
  548.             mark = 0x1;
  549.         }
  550.         }
  551.         if (!PointerIsValid(tuple =
  552.             heap_getnext(scandesc, !(random() & 0x1), &buffer))) {
  553.         puts("*NULL*");
  554.         continue;
  555.         }
  556.         showtup(tuple, buffer, reldesc);
  557.     }
  558.     puts("\nDone");
  559.     heap_endscan(scandesc);
  560.     }
  561.     EndPortalAllocMode();
  562. }
  563. #endif
  564.  
  565.  
  566. /* ----------------
  567.  *    showtup
  568.  * ----------------
  569.  */
  570. void
  571. showtup(tuple, buffer, relation)
  572.     HeapTuple    tuple;
  573.     Buffer    buffer;
  574.     Relation    relation;
  575. {
  576.     char    *value, *fmgr();
  577.     Boolean    isnull;
  578.     struct    typmap    **app;
  579.     int        i, typeindex;
  580.  
  581.     value = (char *)
  582.     heap_getattr(tuple, buffer, ObjectIdAttributeNumber,
  583.           (struct attribute **)NULL, &isnull);
  584.     
  585.     if (isnull) {
  586.     printf("*NULL* < ");
  587.     } else {
  588.     printf("%ld < ", (long)value);
  589.     }
  590.     
  591.     for (i = 0; i < numattr; i++) {
  592.     value = (char *)
  593.         heap_getattr(tuple, buffer, i + 1,
  594.               &reldesc->rd_att.data[0], &isnull);
  595.     if (isnull) {
  596.         printf("<NULL> ");
  597.     } else if (Typ != (struct typmap **)NULL) {
  598.         app = Typ;
  599.         while (*app != NULL && (*app)->am_oid !=
  600.         reldesc->rd_att.data[i]->atttypid) {
  601.         app++;
  602.         }
  603.         if (*app == NULL) {
  604.         printf("Unable to find atttypid in Typ list! %d\n",
  605.             reldesc->rd_att.data[i]->atttypid
  606.         );
  607.         Assert(0);
  608.         }
  609.         printf("%s ", value = fmgr((*app)->am_typ.typoutput, value));
  610.         pfree(value);
  611.     } else {
  612.         typeindex = reldesc->rd_att.data[i]->atttypid - FIRST_TYPE_OID;
  613.         printf("%s ", value = fmgr(Procid[typeindex][(int) Q_OUT], value));
  614.         pfree(value);
  615.     }
  616.     }
  617.     if (!Quiet) printf(">\n");
  618.     if (ShowTime) {
  619.      printf("\t[");
  620.     value = heap_getattr(tuple, buffer, MinAbsoluteTimeAttributeNumber,
  621.               &reldesc->rd_att.data[0], &isnull);
  622.     if (isnull) {
  623.         printf("{*NULL*} ");
  624.     } else if (TimeIsValid((Time)value)) {
  625.         showtime((Time)value);
  626.     }
  627.  
  628.     value = heap_getattr(tuple, buffer, MinCommandIdAttributeNumber,
  629.               &reldesc->rd_att.data[0], &isnull);
  630.     if (isnull) {
  631.         printf("(*NULL*,");
  632.     } else {
  633.         printf("(%u,", (CommandId)value);
  634.     }
  635.     
  636.     value = heap_getattr(tuple, buffer, MinTransactionIdAttributeNumber,
  637.               &reldesc->rd_att.data[0], &isnull);
  638.     
  639.     if (isnull) {
  640.         printf("*NULL*),");
  641.     } else if (!TransactionIdIsValid((TransactionId)value)) {
  642.         printf("-),");
  643.     } else {
  644.         printf("%s)", TransactionIdFormString((TransactionId)value));
  645.         if (!TransactionIdDidCommit((TransactionId)value)) {
  646.         if (TransactionIdDidAbort((TransactionId)value)) {
  647.             printf("*A*");
  648.         } else {
  649.             printf("*InP*");
  650.         }
  651.         }
  652.         value = (char *)TransactionIdGetCommitTime((TransactionId)value);
  653.         if (!TimeIsValid((Time)value)) {
  654.         printf("{-},");
  655.         } else {
  656.         showtime((Time)value);
  657.         printf(",");
  658.         }
  659.     }
  660.     
  661.     value = heap_getattr(tuple, buffer, MaxAbsoluteTimeAttributeNumber,
  662.               &reldesc->rd_att.data[0], &isnull);
  663.     
  664.     if (isnull) {
  665.         printf("{*NULL*} ");
  666.     } else if (TimeIsValid((Time)value)) {
  667.         showtime((Time)value);
  668.     }
  669.  
  670.     value = heap_getattr(tuple, buffer, MaxCommandIdAttributeNumber,
  671.             &reldesc->rd_att.data[0], &isnull);
  672.     
  673.     if (isnull) {
  674.         printf("(*NULL*,");
  675.     } else {
  676.         printf("(%u,", (CommandId)value);
  677.     }
  678.  
  679.     value = heap_getattr(tuple, buffer, MaxTransactionIdAttributeNumber,
  680.             &reldesc->rd_att.data[0], &isnull);
  681.     
  682.     if (isnull) {
  683.         printf("*NULL*)]\n");
  684.     } else if (!TransactionIdIsValid((TransactionId)value)) {
  685.         printf("-)]\n");
  686.     } else {
  687.         printf("%s)", TransactionIdFormString((TransactionId)value));
  688.         value = (char *)TransactionIdGetCommitTime((TransactionId)value);
  689.         if (!TimeIsValid((Time)value)) {
  690.         printf("{-}]\n");
  691.         } else {
  692.         showtime((Time)value);
  693.         printf("]\n");
  694.         }
  695.     }
  696.     }
  697. }
  698.  
  699. /* ----------------
  700.  *    showtime
  701.  * ----------------
  702.  */
  703. void
  704. showtime(time)
  705.     Time time;
  706. {
  707.     Assert(TimeIsValid(time));
  708.     printf("{%d=%s}", time, nabstimeout(time));
  709. }
  710.  
  711.  
  712. /* ----------------
  713.  * DEFINEATTR()
  714.  *
  715.  * define a <field,type> pair
  716.  * if there are n fields in a relation to be created, this routine
  717.  * will be called n times
  718.  * ----------------
  719.  */
  720. void
  721. DefineAttr(name, type, attnum)
  722.     char *name, *type;
  723.     int  attnum;
  724. {
  725.     int     attlen;
  726.     TYPE    t;
  727.  
  728.     if (reldesc != NULL) {
  729.     fputs("Warning: no open relations allowed with 't' command.\n",stderr);
  730.     closerel(relname);
  731.     }
  732.  
  733.     t = (TYPE)gettype(type);
  734.     if (attrtypes[attnum] == (struct attribute *)NULL) 
  735.     attrtypes[attnum] = AllocateAttribute();
  736.     if (Typ != (struct typmap **)NULL) {
  737.     attrtypes[attnum]->atttypid = Ap->am_oid;
  738.     strncpy(attrtypes[attnum]->attname, name, 16);
  739.     if (!Quiet) printf("<%s %s> ", attrtypes[attnum]->attname, type);
  740.     attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
  741.     attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
  742.     attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
  743.     } else {
  744.     attrtypes[attnum]->atttypid = Procid[(int)t][(int)Q_OID];
  745.     strncpy(attrtypes[attnum]->attname,name, 16);
  746.     if (!Quiet) printf("<%s %s> ", attrtypes[attnum]->attname, type);
  747.     attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
  748.     attlen = attrtypes[attnum]->attlen = Procid[(int)t][(int)Q_LEN];
  749.     attrtypes[attnum]->attbyval = (attlen==1) || (attlen==2)||(attlen==4);
  750.     }
  751. }
  752.  
  753.  
  754. /* ----------------
  755.  *    InsertOneTuple
  756.  *    assumes that 'oid' will not be zero.
  757.  * ----------------
  758.  */
  759. void
  760. InsertOneTuple(objectid)
  761.     ObjectId  objectid;
  762. {
  763.     HeapTuple tuple;
  764.     int i;
  765.  
  766.     if (DebugMode) {
  767.     printf("InsertOneTuple oid %d, %d attrs\n", objectid, numattr);
  768.     fflush(stdout);
  769.     }
  770.  
  771.     tuple = heap_formtuple(numattr,attrtypes,values,Blanks);
  772.     if(objectid !=(OID)0) {
  773.     tuple->t_oid=objectid;
  774.     }
  775.     RelationInsertHeapTuple(reldesc,(HeapTuple)tuple,(double *)NULL);
  776.     pfree(tuple);
  777.     if (DebugMode) {
  778.     printf("End InsertOneTuple\n", objectid);
  779.     fflush(stdout);
  780.     }
  781.     /*
  782.      * Reset blanks for next tuple
  783.      */
  784.     for (i = 0; i<numattr; i++)
  785.     Blanks[i] = ' ';
  786. }
  787.  
  788. /* ----------------
  789.  *    InsertOneValue
  790.  * ----------------
  791.  */
  792. void
  793. InsertOneValue(objectid, value, i)
  794.     ObjectId  objectid;
  795.     int          i;
  796.     char     *value;
  797. {
  798.     int        typeindex;
  799.     char    *prt;
  800.     struct typmap **app;
  801.     HeapTuple    tuple;
  802.     char    *fmgr();
  803.  
  804.     if (DebugMode)
  805.     printf("Inserting value: '%s'\n", value);
  806.     if (i < 0 || i >= MAXATTR) {
  807.     printf("i out of range: %d\n", i);
  808.     Assert(0);
  809.     }
  810.  
  811.     if (Typ != (struct typmap **)NULL) {
  812.     struct typmap *ap;
  813.     if (DebugMode)
  814.         puts("Typ != NULL");
  815.     app = Typ;
  816.     while (*app && (*app)->am_oid != reldesc->rd_att.data[i]->atttypid)
  817.        ++app;
  818.     ap = *app;
  819.     if (ap == NULL) {
  820.         printf("Unable to find atttypid in Typ list! %d\n",
  821.             reldesc->rd_att.data[i]->atttypid
  822.         );
  823.         Assert(0);
  824.     }
  825.     if (!Quiet) printf("FMGR-IN/OUT %d, %d\n", ap->am_typ.typinput, 
  826.         ap->am_typ.typoutput);
  827.     values[i] = fmgr(ap->am_typ.typinput, value);
  828.     prt = fmgr(ap->am_typ.typoutput, values[i]);
  829.     if (!Quiet) printf("%s ", prt);
  830.     pfree(prt);
  831.     } else {
  832.     typeindex = attrtypes[i]->atttypid - FIRST_TYPE_OID;
  833.     if (DebugMode)
  834.         printf("Typ == NULL, typeindex = %d idx = %d\n", typeindex, i);
  835.     values[i] = fmgr(Procid[typeindex][(int)Q_IN], value);
  836.     prt = fmgr(Procid[typeindex][(int) Q_OUT], values[i]);
  837.     if (!Quiet) printf("%s ", prt);
  838.     pfree(prt);
  839.     }
  840.     if (DebugMode) {
  841.     puts("End InsertValue");
  842.     fflush(stdout);
  843.     }
  844. }
  845.  
  846. /* ----------------
  847.  *    InsertOneNull
  848.  * ----------------
  849.  */
  850. void
  851. InsertOneNull(i)
  852.     int          i;
  853. {
  854.     if (DebugMode)
  855.     printf("Inserting null\n");
  856.     if (i < 0 || i >= MAXATTR) {
  857.     elog(FATAL, "i out of range (too many attrs): %d\n", i);
  858.     }
  859.     values[i] = (char *)NULL;
  860.     Blanks[i] = 'n';
  861. }
  862.  
  863. /* ----------------
  864.  *    defineindex
  865.  *
  866.  *    This defines an index on the oid attribute of the specified
  867.  *    heap relation.
  868.  * ----------------
  869.  */
  870. void
  871. defineindex(heapName, indexName, accessMethodName, attributeList)
  872.     char  *heapName;
  873.     char  *indexName;
  874.     char  *accessMethodName;
  875.     List  attributeList;
  876. {
  877.     Relation    cur_relation;
  878.  
  879.     DefineIndex(heapName,
  880.         indexName,
  881.         accessMethodName,
  882.         attributeList,
  883.         LispNil,
  884.         LispNil);
  885.     /*
  886.      * All of the rest of this routine is needed only because in bootstrap
  887.      * processing we don't increment xact id's.  The normal DefineIndex
  888.      * code replaces a pg_class tuple with updated info including the
  889.      * relhasindex flag (which we need to have updated).  Unfortunately, 
  890.      * there are always two indices defined on each catalog causing us to 
  891.      * update the same pg_class tuple twice for each catalog getting an 
  892.      * index during bootstrap resulting in the ghost tuple problem (see 
  893.      * heap_replace).  To get around this we change the relhasindex 
  894.      * field ourselves in this routine keeping track of what catalogs we 
  895.      * already changed so that we don't modify those tuples twice.  The 
  896.      * normal mechanism for updating pg_class is disabled during bootstrap.
  897.      *
  898.      *        -mer 
  899.      */
  900.     cur_relation = heap_openr(heapName);
  901.     if (! RelationIsValid(cur_relation))
  902.             elog(WARN, "defineindex: could not open %s relation", heapName);
  903.  
  904.     if (!BootstrapAlreadySeen(cur_relation->rd_id))
  905.     UpdateStats(cur_relation->rd_id, 0, true);
  906. }
  907.  
  908. #define MORE_THAN_THE_NUMBER_OF_CATALOGS 256
  909.  
  910. bool
  911. BootstrapAlreadySeen(id)
  912.     ObjectId id;
  913. {
  914.     static ObjectId seenArray[MORE_THAN_THE_NUMBER_OF_CATALOGS];
  915.     static int nseen = 0;
  916.     bool seenthis;
  917.     int i;
  918.  
  919.     seenthis = false;
  920.  
  921.     for (i=0; i < nseen; i++)
  922.     {
  923.     if (seenArray[i] == id)
  924.     {
  925.         seenthis = true;
  926.         break;
  927.     }
  928.     }
  929.     if (!seenthis)
  930.     {
  931.     seenArray[nseen] = id;
  932.     nseen++;
  933.     }
  934.     return (seenthis);
  935. }
  936.  
  937.  
  938. /* ----------------
  939.  *    handletime
  940.  * ----------------
  941.  */
  942. void
  943. handletime()
  944. {
  945.     int     numberOfTimes;
  946.     char    firstTime[80];
  947.     char    secondTime[80];
  948.     Time    time1;
  949.     Time    time2;
  950.  
  951.     if (scanf("%d", &numberOfTimes) != 1) {
  952.     fputs("Error: failed to read number of time fields\n", stderr);
  953.     err();
  954.     }
  955.     if (numberOfTimes < -1 || numberOfTimes > 2) {
  956.     elog(
  957.         WARN, 
  958.         "number of time fields (%d) is not -1, 0, 1, or 2\n",
  959.         numberOfTimes
  960.     );
  961.     } else if (numberOfTimes == -1) {
  962.     ShowTime = !ShowTime;
  963.     return;
  964.     } else if (numberOfTimes == 0) {
  965.     StandardTimeQual = NowTimeQual;
  966.     puts("Time range reset to \"now\"");
  967.     } else if (numberOfTimes == 1) {
  968.     if (scanf("%[^\n]", firstTime) != 1) {
  969.         fputs("Error: failed to read time\n", stderr);
  970.         err();
  971.     }
  972.     time1 = nabstimein(firstTime);
  973.     if (!Quiet) printf("*** You entered \"%s\"", firstTime);
  974.     if (time1 == INVALID_ABSTIME) {
  975.         if (!Quiet) 
  976.             printf(" which is INVALID (time range unchanged).\n");
  977.     } else {
  978.         if (!Quiet) 
  979.             printf(" with representation %d.\n", time1);
  980.         bcopy(
  981.         (char *)TimeFormSnapshotTimeQual(time1),
  982.         (char *)&StandardTimeQualSpace,
  983.         sizeof StandardTimeQualSpace
  984.         );
  985.         StandardTimeQual = (TimeQual)&StandardTimeQualSpace;
  986.     }
  987.     } else {    /* numberOfTimes == 2 */
  988.     if (scanf("%[^,],%[^\n]", firstTime, secondTime) != 2) {
  989.         fputs("Error: failed to read both times\n", stderr);
  990.         err();
  991.     }
  992.     if (!Quiet) 
  993.         printf("*** You entered \"%s\" and \"%s\"\n", firstTime, secondTime);
  994.     time1 = nabstimein(firstTime);
  995.     time2 = nabstimein(secondTime);
  996.     if (time1 == INVALID_ABSTIME) {
  997.         time1 = InvalidTime;
  998.         if (time2 == INVALID_ABSTIME) {
  999.         time2 = InvalidTime;
  1000.         if (!Quiet) printf("*** range is [,].\n");
  1001.         } else {
  1002.         if (!Quiet) printf("*** range is [,%d].\n", time2);
  1003.         }
  1004.     } else {
  1005.         if (time2 == INVALID_ABSTIME) {
  1006.         time2 = InvalidTime;
  1007.         if (!Quiet) printf("*** range is [%d,].\n", time1);
  1008.         } else {
  1009.         if (!Quiet) printf("*** range is [%d,%d].\n", time1, time2);
  1010.         }
  1011.     }
  1012.     bcopy(
  1013.         (char *)TimeFormRangedTimeQual(time1, time2),
  1014.         (char *)&StandardTimeQualSpace,
  1015.         sizeof StandardTimeQualSpace
  1016.     );
  1017.     StandardTimeQual = (TimeQual)&StandardTimeQualSpace;
  1018.     }
  1019. }
  1020.  
  1021. /* ----------------
  1022.  *    cleanup
  1023.  * ----------------
  1024.  */
  1025. void
  1026. cleanup()
  1027. {
  1028.     static    int    beenhere = 0;
  1029.      
  1030.     if (!beenhere)
  1031.     beenhere = 1;
  1032.     else {
  1033.     elog(FATAL,"Memory manager fault: cleanup called twice.\n", stderr);
  1034.     exitpg(1);
  1035.     }
  1036.     if (reldesc != (Relation)NULL) {
  1037.     heap_close(reldesc);
  1038.     }
  1039.     CommitTransactionCommand();
  1040.     exitpg(Warnings);
  1041. }
  1042.  
  1043. /* ----------------
  1044.  *    gettype
  1045.  * ----------------
  1046.  */
  1047. int
  1048. gettype(type)
  1049.     char *type;
  1050. {
  1051.     int        i;
  1052.     Relation    rdesc;
  1053.     HeapScanDesc    sdesc;
  1054.     HeapTuple    tup;
  1055.     struct    typmap    **app;
  1056.     extern    char    TYPE_R[];
  1057.  
  1058.     if (Typ != (struct typmap **)NULL) {
  1059.     for (app = Typ; *app != (struct typmap *)NULL; app++) {
  1060.         if (strcmp((*app)->am_typ.typname, type) == 0) {
  1061.         Ap = *app;
  1062.         return((*app)->am_oid);
  1063.         }
  1064.     }
  1065.     } else {
  1066.     for (i = 0; i <= (int)TY_LAST; i++) {
  1067.         if (strcmp(type, typestr[i]) == 0) {
  1068.         return(i);
  1069.         }
  1070.     }
  1071.     if (DebugMode)
  1072.         printf("backendsup.c: External Type: %s\n", type);
  1073.         rdesc = heap_openr(TYPE_R);
  1074.         sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
  1075.     i = 0;
  1076.     while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL)))
  1077.         ++i;
  1078.     heap_endscan(sdesc);
  1079.     app = Typ = ALLOC(struct typmap *, i + 1);
  1080.     while (i-- > 0)
  1081.         *app++ = ALLOC(struct typmap, 1);
  1082.     *app = (struct typmap *)NULL;
  1083.     sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
  1084.     app = Typ;
  1085.     while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL))) {
  1086.         (*app)->am_oid = tup->t_oid;
  1087.         bcopy(
  1088.         (char *)GETSTRUCT(tup), 
  1089.         (char *)&(*app++)->am_typ,
  1090.             sizeof ((*app)->am_typ)
  1091.         );
  1092.         }
  1093.         heap_endscan(sdesc);
  1094.         heap_close(rdesc);
  1095.         return(gettype(type));
  1096.     }
  1097.     elog(WARN, "Error: unknown type '%s'.\n", type);
  1098.     err();
  1099.     /* NOTREACHED */
  1100. }
  1101.  
  1102. /* ----------------
  1103.  *    AllocateAttribute
  1104.  * ----------------
  1105.  */
  1106. struct attribute * /* XXX */
  1107. AllocateAttribute()
  1108. {
  1109.     struct attribute    *attribute = new(struct attribute); /* XXX */
  1110.  
  1111.     if (!PointerIsValid(attribute)) {
  1112.     elog(FATAL, "AllocateAttribute: malloc failed");
  1113.     }
  1114.     bzero((Pointer)attribute, sizeof *attribute);
  1115.  
  1116.     return (attribute);
  1117. }
  1118.  
  1119. /* ----------------
  1120.  *    MapEscape
  1121.  * ----------------
  1122.  */
  1123. #define isoctal(c) ((c)>='0' && (c) <= '7')
  1124.  
  1125. unsigned char 
  1126. MapEscape(s)
  1127.     char **s;
  1128. {
  1129.     int i;
  1130.     char octal[4];
  1131.     switch(*(*s)++) {
  1132.     case '\\':
  1133.     return '\\';
  1134.     case 'b':
  1135.     return '\b';
  1136.     case 'f':
  1137.      return '\f';
  1138.     case 'r':
  1139.     return '\r';
  1140.     case 't':
  1141.     return '\t';
  1142.     case '"':
  1143.     return '"';
  1144.     case '\'':
  1145.     return '\'';
  1146.     case '0': 
  1147.     case '1': 
  1148.     case '2': 
  1149.     case '3': 
  1150.     case '4': 
  1151.     case '5':
  1152.     case '6': 
  1153.     case '7':
  1154.     for (--*s,i=0;isoctal((*s)[i]) && (i<3); ++i)
  1155.         octal[i]=(*s)[i];
  1156.     *s += i;
  1157.     octal[i] = '\0';
  1158.     if ((i = strtol(octal,0,8)) <= 0377) 
  1159.         return ((char)i);
  1160.     default:
  1161.     break;
  1162.     }
  1163.     elog(WARN,"Bad Escape sequence");
  1164.     return *((*s)++); /* ignore */
  1165. }
  1166.  
  1167. /* ----------------
  1168.  *    EnterString
  1169.  *    returns the string table position of the identifier
  1170.  *    passed to it.  We add it to the table if we can't find it.
  1171.  * ----------------
  1172.  */
  1173. int 
  1174. EnterString (str)
  1175.     char    *str;
  1176. {
  1177.     hashnode    *node;
  1178.     int        len;
  1179.     
  1180.     len= strlen(str);
  1181.     
  1182.     if ( (node = FindStr(str, len, 0)) != NULL)
  1183.     return (node->strnum);
  1184.     else {
  1185.     node = AddStr(str, len, 0);
  1186.     return (node->strnum);
  1187.     }
  1188. }
  1189.  
  1190. /* ----------------
  1191.  *    LexIDStr
  1192.  *    when given an idnum into the 'string-table' return the string
  1193.  *    associated with the idnum
  1194.  * ----------------
  1195.  */
  1196. char *
  1197. LexIDStr(ident_num) 
  1198.     int ident_num;
  1199. {
  1200.     return(strtable[ident_num]->s);
  1201. }    
  1202.  
  1203.  
  1204. /* ----------------
  1205.  *    CompHash
  1206.  *
  1207.  *     Compute a hash function for a given string.  We look at the first,
  1208.  *     the last, and the middle character of a string to try to get spread
  1209.  *     the strings out.  The function is rather arbitrary, except that we
  1210.  *     are mod'ing by a prime number.
  1211.  * ----------------
  1212.  */
  1213. int 
  1214. CompHash (str, len)
  1215.     char *str;
  1216.     int    len;
  1217. {
  1218.     register int result;
  1219.     
  1220.     result =(NUM * str[0] + NUMSQR * str[len-1] + NUMCUBE * str[(len-1)/2]);
  1221.  
  1222.     return (result % HASHTABLESIZE);
  1223.  
  1224. }
  1225.  
  1226. /* ----------------
  1227.  *    FindStr
  1228.  *
  1229.  *     This routine looks for the specified string in the hash
  1230.  *     table.  It returns a pointer to the hash node found,
  1231.  *     or NULL if the string is not in the table.
  1232.  * ----------------
  1233.  */
  1234. hashnode *
  1235. FindStr (str, length, mderef)
  1236.     char    *str;
  1237.     int        length;
  1238.     hashnode   *mderef;
  1239. {
  1240.     hashnode    *node;
  1241.     node = hashtable [CompHash (str, length)];
  1242.     while (node != NULL) {
  1243.     /*
  1244.      * We must differentiate between string constants that
  1245.      * might have the same value as a identifier
  1246.      * and the identifier itself.
  1247.      */
  1248.     if (!strcmp(str, strtable[node->strnum]->s)) {
  1249.         return(node);  /* no need to check */
  1250.     } else {
  1251.         node = node->next;
  1252.     }
  1253.     }
  1254.     /* Couldn't find it in the list */
  1255.     return (NULL);
  1256. }
  1257.  
  1258. /* ----------------
  1259.  *    AddStr
  1260.  *
  1261.  *     This function adds the specified string, along with its associated
  1262.  *     data, to the hash table and the string table.  We return the node
  1263.  *     so that the calling routine can find out the unique id that AddStr
  1264.  *     has assigned to this string.
  1265.  * ----------------
  1266.  */
  1267. hashnode *
  1268. AddStr(str, strlength, mderef)
  1269.     char *str;
  1270.     int     strlength;
  1271.     int  mderef;
  1272. {
  1273.     hashnode    *temp, *trail, *newnode;
  1274.     int        hashresult;
  1275.     char    *stroverflowmesg =
  1276. "There are too many string constants and identifiers for\
  1277.  the compiler to handle.";
  1278.  
  1279.     if (++strtable_end == STRTABLESIZE) {
  1280.     /* Error, string table overflow, so we Punt */
  1281.     elog(FATAL, stroverflowmesg);
  1282.     }
  1283.  
  1284.     strtable[strtable_end] = new(macro);
  1285.     strtable [strtable_end]->s = malloc((unsigned) strlength + 1);
  1286.     strtable[strtable_end]->mderef = 0;
  1287.     strcpy (strtable[strtable_end]->s, str);
  1288.  
  1289.     /* Now put a node in the hash table */
  1290.  
  1291.     newnode = new(hashnode);
  1292.     newnode->strnum = strtable_end;
  1293.     newnode->next = NULL;
  1294.  
  1295.     /* Find out where it goes */
  1296.  
  1297.     hashresult = CompHash (str, strlength);
  1298.     if (hashtable [hashresult] == NULL) {
  1299.     hashtable [hashresult] = newnode;
  1300.     } else {            /* There is something in the list */
  1301.     trail = hashtable [hashresult];
  1302.     temp = trail->next;
  1303.     while (temp != NULL) {
  1304.         trail = temp;
  1305.         temp = temp->next;
  1306.     }
  1307.     trail->next = newnode;
  1308.     }
  1309.     return (newnode);
  1310. }
  1311.  
  1312. /* ----------------
  1313.  *    printhashtable
  1314.  *
  1315.  *     This routine dumps out the hash table for inspection.
  1316.  * ----------------
  1317.  */
  1318. void
  1319. printhashtable()
  1320. {
  1321.     register int i;
  1322.     hashnode *hashptr;
  1323.  
  1324.     if (Quiet) return;
  1325.  
  1326.     fprintf (stderr, "\n\nHash Table:\n");
  1327.     for (i = 0; i < HASHTABLESIZE; i++) {
  1328.         if (hashtable[i] != NULL) {
  1329.         fprintf (stderr, "Position: %d\n", i);
  1330.         hashptr = hashtable[i];
  1331.         do {
  1332.             fprintf (stderr, "\tString #%d", hashptr->strnum);
  1333.         hashptr = hashptr->next;
  1334.         } while (hashptr != NULL);
  1335.     }
  1336.     }
  1337. }
  1338.  
  1339. /* ----------------
  1340.  *    printstrtable
  1341.  *
  1342.  *    This routine dumps out the string table for inspection.
  1343.  * ----------------
  1344.  */
  1345. void
  1346. printstrtable ()
  1347. {
  1348.     register int i;
  1349.  
  1350.     if (Quiet) return;
  1351.  
  1352.     fprintf (stderr, "\nString Table:\n");
  1353.     for (i = 0; i <= strtable_end; i++) {
  1354.     fprintf (stderr, "#%d: \"%s\";\t   ", i, strtable[i]->s);
  1355.     if (i % 3 == 0 && i > 0)
  1356.         fprintf (stderr, "\n");
  1357.     }
  1358.     fprintf (stderr, "\n");
  1359. }
  1360.  
  1361. /* ----------------
  1362.  *    emalloc
  1363.  *
  1364.  *    Error checked version of malloc.
  1365.  * ----------------
  1366.  */
  1367. char *
  1368. emalloc (size)
  1369.     unsigned size;
  1370. {
  1371.     char *p;
  1372.  
  1373.     if ((p = malloc (size)) == NULL)
  1374.     elog (FATAL,"Memory Allocation Error\n");
  1375.     return (p);
  1376. }
  1377.  
  1378. /* ----------------
  1379.  *    LookUpMacro()
  1380.  *
  1381.  *      takes an index into the string table and converts it into the
  1382.  *      appropriate "string"
  1383.  * ----------------
  1384.  */
  1385. int
  1386. LookUpMacro(xmacro)
  1387.     char *xmacro;
  1388. {
  1389.     hashnode *node;
  1390.     int macro_indx;
  1391.  
  1392.     if (node = FindStr(xmacro,strlen(xmacro),0))
  1393.     macro_indx = node->strnum;
  1394.   
  1395.     if (strtable[macro_indx]->mderef == 0)
  1396.     elog(WARN,"Dereferencing non-existent macro");
  1397.     
  1398.     return(strtable[macro_indx]->mderef);
  1399. }
  1400.  
  1401. /* ----------------
  1402.  *    DefineMacro
  1403.  *
  1404.  *    takes two identifiers and links them up
  1405.  *    by putting a pointer between id1 and id2
  1406.  *    (the identifiers pointed to by indx1 and indx2
  1407.  * ----------------
  1408.  */
  1409. void
  1410. DefineMacro(indx1, indx2)
  1411.     int indx1, indx2;
  1412. {
  1413.     strtable[indx1]->mderef = indx2;
  1414.     if (strtable[indx1]->mderef != 0)
  1415.     elog(WARN,"Warning :redefinition of macro\n");
  1416. }
  1417.  
  1418. /* ----------------
  1419.  *    printmacros
  1420.  * ----------------
  1421.  */
  1422. void
  1423. printmacros()
  1424. {
  1425.     register int i;
  1426.  
  1427.     fprintf(stdout,"Macro Table:\n");
  1428.     for( i = 0;i < strtable_end; ++i) {
  1429.     if (strtable[i]->mderef != 0)
  1430.         printf("\"%s\" = \"%s\"\n",strtable[i]->s,
  1431.                 strtable[strtable[i]->mderef]->s);
  1432.     }
  1433. }
  1434.  
  1435.